//build:20240715
//To simplify the use of the micro-light communication protocol for UART components, the UART is encapsulated in this worker. Users only need to subscribe to events in the eventcenter to listen to UART.
import log from './dxLogger.js'
import uart from './dxUart.js'
import common from './dxCommon.js';
import dxMap from './dxMap.js'
import * as os from "os";
import std from './dxStd.js'
const map = dxMap.get('default')
const id = "{{id}}"
const options = map.get("__vguart__run_init" + id)
const timeout = 100
const longTimeout = 500

function run() {
    uart.open(options.type, options.path, options.id)
    log.info('vg uart start......,id =', id)
    std.setInterval(() => {
        try {
            // Receive data mode
            if (options.passThrough) {
                // Pass-through mode, compatible with Wiegand and similar systems.
                passThrough()
            }
            if(options.type == uart.TYPE.USBHID){
                receiveUsb() 
            } else {
                // Low-light communication protocol mode
                receive()
            }
        } catch (error) {
            log.error(error)
        }
    }, 10)
}

// Pass-through mode
function passThrough() {
    let pack = [];
    let buffer = readOne()
    while (buffer !== null) {
        pack.push(buffer)
        os.sleep(10)
        buffer = readOne()
    }
    if (pack.length !== 0) {
        __bus.fire(uart.VG.RECEIVE_MSG + options.id, pack)//When you call `bus.newworker`, you will import `eventbus` as `__bus`.
    }
}

function receive() {
    //The first two bytes must be 55aa
    let buffer = readOne()
    if (buffer === null) {
        return;
    }
    if (buffer == 85) {//0x55
        buffer = readOne()
        if (buffer != 170) {//0xaa
            return;
        }
    } else {
        return;
    }
    let pack = {};
    // Read command word (occupies 1 byte)
    buffer = readOne()
    if (buffer === null) {
        return;
    }
    pack.cmd = buffer
    if (options.result) {
        // Read the result word (occupies 1 byte)
        buffer = readOne()
        if (buffer === null) {
            return;
        }
        pack.result = buffer;
    } else {
        pack.result = 0//0 does not affect the calculation result of bcc.
    }
    // The command header has been parsed; the length word (occupying 2 bytes) is now being read.
    let len1 = readOne()
    if (len1 === null) {
        return;
    }
    let len2 = readOne()
    if (len2 === null) {
        return;
    }
    // Parse the length word to obtain the length of the data field.
    let len = len1 + len2 * 256
    // Read the specified data length based on the length word.
    pack.length = len
    if (len > 0) {
        buffer = uart.receive(len, longTimeout, options.id)
        if (buffer === null) {
            return;
        }
        pack.data = Array.from(buffer);
    } else {
        pack.data = 0
    }
    // Read 1 byte of parity bit
    buffer = readOne()
    if (buffer === null) {
        return;
    }
    let bcc = valid(pack, buffer)
    let res = { cmd: int2hex(pack.cmd), length: pack.length, bcc: bcc }
    if (pack.length > 0) {
        res.data = common.arrToHex(pack.data)
    }
    if (options.result) {
        res.result = int2hex(pack.result)
    }
    __bus.fire(uart.VG.RECEIVE_MSG + options.id, res)//When you call `bus.newworker`, you will import `eventbus` as `__bus`.
}


function receiveUsb() {
    let arr = uart.receive(1024, 100, options.id)
    if (arr && arr[0] == 0x55 && arr[1] == 0xAA) {
        let cmd = arr[2]
        let dlen = arr[4] * 256 + arr[3]
        if (dlen > (1024 - 6)) {
            let tempLen = dlen - 1024 + 5 
            while(tempLen >= 0){
                let tempArr = uart.receive(1024, 100, options.id)
                tempLen = tempLen - tempArr.length
                let newArr = new Uint8Array(arr.length + tempArr.length)
                newArr.set(arr)
                newArr.set(tempArr, arr.length)
                arr = newArr
            }
        }
        let data = (dlen == 0 ? [] : Object.values(arr.slice(5, 5 + dlen)))
        let bcc = common.calculateBcc([0x55, 0xAA, arr[2], arr[3], arr[4]].concat(data))
        data = data.map(v => v.toString(16).padStart(2, '0')).join('')
        if (bcc == arr[5 + dlen]) {
            let res = { "cmd": cmd.toString(16).padStart(2, '0'), "length": dlen, "data": data, "bcc": true }
            __bus.fire(uart.VG.RECEIVE_MSG + options.id, res)//When you call `bus.newworker`, you will import `eventbus` as `__bus`.
        }
    }
}

function valid(pack, bcc) {
    let temp = common.calculateBcc([0x55, 0xaa, pack.cmd, pack.result, pack.length % 256, Math.floor(pack.length / 256)].concat(pack.data))
    return temp === bcc
}
function readOne() {
    let buffer = uart.receive(1, timeout, options.id)
    if (buffer) {
        return parseInt(buffer);
    }
    return null
}
function int2hex(num) {
    return num.toString(16).padStart(2, '0')
}

try {
    run()
} catch (error) {
    log.error(error, error.stack)
}